{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "Collapsed": "false"
   },
   "source": [
    "# Train a CNN\n",
    "\n",
    "In this notebook we will go through all the steps required to train a fully convolutional neural network. Because this takes a while and uses a lot of GPU RAM a separate command line script (`train_nn.py`) is also provided in the `src` directory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "# Depending on your combination of package versions, this can raise a lot of TF warnings... \n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import xarray as xr\n",
    "import tensorflow as tf\n",
    "import tensorflow.keras as keras\n",
    "from tensorflow.keras.layers import *\n",
    "import tensorflow.keras.backend as K\n",
    "import seaborn as sns\n",
    "import pickle\n",
    "from src.score import *\n",
    "from collections import OrderedDict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "def limit_mem():\n",
    "    \"\"\"By default TF uses all available GPU memory. This function prevents this.\"\"\"\n",
    "    config = tf.ConfigProto()\n",
    "    config.gpu_options.allow_growth = True\n",
    "    tf.Session(config=config)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "limit_mem()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "sns.set_style('darkgrid')\n",
    "sns.set_context('notebook')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "DATADIR = '/data/weather-benchmark/5.625deg/'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "Collapsed": "false"
   },
   "source": [
    "## Create data generator\n",
    "\n",
    "First up, we want to write our own Keras data generator. The key advantage to just feeding in numpy arrays is that we don't have to load the data twice because our intputs and outputs are the same data just offset by the lead time. Since the dataset is quite large and we might run out of CPU RAM this is important."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "# Load the validation subset of the data: 2017 and 2018\n",
    "z500_valid = load_test_data(f'{DATADIR}geopotential_500', 'z')\n",
    "t850_valid = load_test_data(f'{DATADIR}temperature_850', 't')\n",
    "valid = xr.merge([z500_valid, t850_valid])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "z = xr.open_mfdataset(f'{DATADIR}geopotential_500/*.nc', combine='by_coords')\n",
    "t = xr.open_mfdataset(f'{DATADIR}temperature_850/*.nc', combine='by_coords')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "# For the data generator all variables have to be merged into a single dataset.\n",
    "datasets = [z, t]\n",
    "ds = xr.merge(datasets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "ds_train = ds.sel(time=slice('2015', '2016'))\n",
    "ds_test = ds.sel(time=slice('2017', '2018'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "class DataGenerator(keras.utils.Sequence):\n",
    "    def __init__(self, ds, var_dict, lead_time, batch_size=32, shuffle=True, load=True, mean=None, std=None):\n",
    "        \"\"\"\n",
    "        Data generator for WeatherBench data.\n",
    "        Template from https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly\n",
    "        Args:\n",
    "            ds: Dataset containing all variables\n",
    "            var_dict: Dictionary of the form {'var': level}. Use None for level if data is of single level\n",
    "            lead_time: Lead time in hours\n",
    "            batch_size: Batch size\n",
    "            shuffle: bool. If True, data is shuffled.\n",
    "            load: bool. If True, datadet is loaded into RAM.\n",
    "            mean: If None, compute mean from data.\n",
    "            std: If None, compute standard deviation from data.\n",
    "        \"\"\"\n",
    "        self.ds = ds\n",
    "        self.var_dict = var_dict\n",
    "        self.batch_size = batch_size\n",
    "        self.shuffle = shuffle\n",
    "        self.lead_time = lead_time\n",
    "\n",
    "        data = []\n",
    "        generic_level = xr.DataArray([1], coords={'level': [1]}, dims=['level'])\n",
    "        for var, levels in var_dict.items():\n",
    "            try:\n",
    "                data.append(ds[var].sel(level=levels))\n",
    "            except ValueError:\n",
    "                data.append(ds[var].expand_dims({'level': generic_level}, 1))\n",
    "\n",
    "        self.data = xr.concat(data, 'level').transpose('time', 'lat', 'lon', 'level')\n",
    "        self.mean = self.data.mean(('time', 'lat', 'lon')).compute() if mean is None else mean\n",
    "        self.std = self.data.std('time').mean(('lat', 'lon')).compute() if std is None else std\n",
    "        # Normalize\n",
    "        self.data = (self.data - self.mean) / self.std\n",
    "        self.n_samples = self.data.isel(time=slice(0, -lead_time)).shape[0]\n",
    "        self.init_time = self.data.isel(time=slice(None, -lead_time)).time\n",
    "        self.valid_time = self.data.isel(time=slice(lead_time, None)).time\n",
    "\n",
    "        self.on_epoch_end()\n",
    "\n",
    "        # For some weird reason calling .load() earlier messes up the mean and std computations\n",
    "        if load: print('Loading data into RAM'); self.data.load()\n",
    "\n",
    "    def __len__(self):\n",
    "        'Denotes the number of batches per epoch'\n",
    "        return int(np.ceil(self.n_samples / self.batch_size))\n",
    "\n",
    "    def __getitem__(self, i):\n",
    "        'Generate one batch of data'\n",
    "        idxs = self.idxs[i * self.batch_size:(i + 1) * self.batch_size]\n",
    "        X = self.data.isel(time=idxs).values\n",
    "        y = self.data.isel(time=idxs + self.lead_time).values\n",
    "        return X, y\n",
    "\n",
    "    def on_epoch_end(self):\n",
    "        'Updates indexes after each epoch'\n",
    "        self.idxs = np.arange(self.n_samples)\n",
    "        if self.shuffle == True:\n",
    "            np.random.shuffle(self.idxs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "# then we need a dictionary for all the variables and levels we want to extract from the dataset\n",
    "dic = OrderedDict({'z': None, 't': None})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "bs=32\n",
    "lead_time=6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loading data into RAM\n",
      "Loading data into RAM\n",
      "CPU times: user 4.25 s, sys: 4.11 s, total: 8.36 s\n",
      "Wall time: 1.53 s\n"
     ]
    }
   ],
   "source": [
    "# Create a training and validation data generator. Use the train mean and std for validation as well.\n",
    "%%time\n",
    "dg_train = DataGenerator(\n",
    "    ds_train.sel(time=slice('2015', '2015')), dic, lead_time, batch_size=bs, load=True)\n",
    "dg_valid = DataGenerator(\n",
    "    ds_train.sel(time=slice('2016', '2016')), dic, lead_time, batch_size=bs, mean=dg_train.mean, std=dg_train.std, shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<xarray.DataArray 'z' (level: 2)>\n",
       " array([54124.863,   274.798], dtype=float32)\n",
       " Coordinates:\n",
       "   * level    (level) int64 850 850, <xarray.DataArray 'z' (level: 2)>\n",
       " array([1110.1985   ,    5.6419535], dtype=float32)\n",
       " Coordinates:\n",
       "   * level    (level) int64 850 850)"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dg_train.mean, dg_train.std"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loading data into RAM\n"
     ]
    }
   ],
   "source": [
    "# Now also a generator for testing. Impartant: Shuffle must be False!\n",
    "dg_test = DataGenerator(ds_test, dic, lead_time, batch_size=bs, mean=dg_train.mean, std=dg_train.std, shuffle=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "Collapsed": "false"
   },
   "source": [
    "## Create and train model\n",
    "\n",
    "Next up, we need to create the model architecture. Here we will use a fully connected convolutional network. Because the Earth is periodic in longitude, we want to use a periodic convolution in the lon-direction. This is not implemented in Keras, so we have to do it manually."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "class PeriodicConv2D(tf.keras.layers.Conv2D):\n",
    "    \"\"\"Convolution with periodic padding in second spatial dimension (lon)\"\"\"\n",
    "    def __init__(self, filters, kernel_size, **kwargs):\n",
    "        assert type(kernel_size) is int, 'Periodic convolutions only works for square kernels.'\n",
    "        self.pad_width = (kernel_size - 1) // 2\n",
    "        super().__init__(filters, kernel_size, **kwargs)\n",
    "        assert self.padding == 'valid', 'Periodic convolution only works for valid padding.'\n",
    "        assert sum(self.strides) == 2, 'Periodic padding only works for stride (1, 1)'\n",
    "    \n",
    "    def _pad(self, inputs):\n",
    "        # Input: [samples, lat, lon, filters]\n",
    "        # Periodic padding in lon direction\n",
    "        inputs_padded = tf.concat(\n",
    "            [inputs[:, :, -self.pad_width:, :], inputs, inputs[:, :, :self.pad_width, :]], axis=2)\n",
    "        # Zero padding in the lat direction\n",
    "        inputs_padded = tf.pad(inputs_padded, [[0, 0], [self.pad_width, self.pad_width], [0, 0], [0, 0]])\n",
    "        return inputs_padded\n",
    "\n",
    "    def __call__(self, inputs, *args, **kwargs):\n",
    "        # Unfortunate workaround necessary for TF < 1.13\n",
    "        inputs_padded = Lambda(self._pad)(inputs)\n",
    "        return super().__call__(inputs_padded, *args, **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "def build_cnn(filters, kernels, input_shape, activation='elu', dr=0):\n",
    "    \"\"\"Fully convolutional network\"\"\"\n",
    "    x = input = Input(shape=input_shape)\n",
    "    for f, k in zip(filters[:-1], kernels[:-1]):\n",
    "        x = PeriodicConv2D(f, k, activation=activation)(x)\n",
    "        if dr > 0: x = Dropout(dr)(x)\n",
    "    output = PeriodicConv2D(filters[-1], kernels[-1])(x)\n",
    "    return keras.models.Model(input, output)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /home/rasp/miniconda3/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Call initializer instance with the dtype argument instead of passing it to the constructor\n"
     ]
    }
   ],
   "source": [
    "cnn = build_cnn([64, 64, 64, 64, 2], [5, 5, 5, 5, 5], (32, 64, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "cnn.compile(keras.optimizers.Adam(1e-4), 'mse')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"model\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "input_1 (InputLayer)         [(None, 32, 64, 2)]       0         \n",
      "_________________________________________________________________\n",
      "lambda (Lambda)              (None, 36, 68, 2)         0         \n",
      "_________________________________________________________________\n",
      "periodic_conv2d (PeriodicCon (None, 32, 64, 32)        1632      \n",
      "_________________________________________________________________\n",
      "lambda_1 (Lambda)            (None, 36, 68, 32)        0         \n",
      "_________________________________________________________________\n",
      "periodic_conv2d_1 (PeriodicC (None, 32, 64, 64)        51264     \n",
      "_________________________________________________________________\n",
      "lambda_2 (Lambda)            (None, 36, 68, 64)        0         \n",
      "_________________________________________________________________\n",
      "periodic_conv2d_2 (PeriodicC (None, 32, 64, 64)        102464    \n",
      "_________________________________________________________________\n",
      "lambda_3 (Lambda)            (None, 36, 68, 64)        0         \n",
      "_________________________________________________________________\n",
      "periodic_conv2d_3 (PeriodicC (None, 32, 64, 64)        102464    \n",
      "_________________________________________________________________\n",
      "lambda_4 (Lambda)            (None, 36, 68, 64)        0         \n",
      "_________________________________________________________________\n",
      "periodic_conv2d_4 (PeriodicC (None, 32, 64, 2)         3202      \n",
      "=================================================================\n",
      "Total params: 261,026\n",
      "Trainable params: 261,026\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "cnn.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/100\n",
      "274/274 [==============================] - 13s 47ms/step - loss: 0.3964 - val_loss: 0.0900\n",
      "Epoch 2/100\n",
      "274/274 [==============================] - 10s 36ms/step - loss: 0.0726 - val_loss: 0.0636\n",
      "Epoch 3/100\n",
      "274/274 [==============================] - 10s 38ms/step - loss: 0.0586 - val_loss: 0.0559\n",
      "Epoch 4/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0533 - val_loss: 0.0526\n",
      "Epoch 5/100\n",
      "274/274 [==============================] - 10s 36ms/step - loss: 0.0504 - val_loss: 0.0500\n",
      "Epoch 6/100\n",
      "274/274 [==============================] - 10s 36ms/step - loss: 0.0486 - val_loss: 0.0481\n",
      "Epoch 7/100\n",
      "274/274 [==============================] - 10s 36ms/step - loss: 0.0471 - val_loss: 0.0477\n",
      "Epoch 8/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0461 - val_loss: 0.0461\n",
      "Epoch 9/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0452 - val_loss: 0.0453\n",
      "Epoch 10/100\n",
      "274/274 [==============================] - 10s 35ms/step - loss: 0.0447 - val_loss: 0.0447\n",
      "Epoch 11/100\n",
      "274/274 [==============================] - 10s 36ms/step - loss: 0.0438 - val_loss: 0.0444\n",
      "Epoch 12/100\n",
      "274/274 [==============================] - 10s 35ms/step - loss: 0.0434 - val_loss: 0.0439\n",
      "Epoch 13/100\n",
      "274/274 [==============================] - 10s 38ms/step - loss: 0.0427 - val_loss: 0.0440\n",
      "Epoch 14/100\n",
      "274/274 [==============================] - 10s 36ms/step - loss: 0.0422 - val_loss: 0.0435\n",
      "Epoch 15/100\n",
      "274/274 [==============================] - 10s 38ms/step - loss: 0.0417 - val_loss: 0.0431\n",
      "Epoch 16/100\n",
      "274/274 [==============================] - 10s 38ms/step - loss: 0.0413 - val_loss: 0.0431\n",
      "Epoch 17/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0409 - val_loss: 0.0418\n",
      "Epoch 18/100\n",
      "274/274 [==============================] - 10s 38ms/step - loss: 0.0404 - val_loss: 0.0407\n",
      "Epoch 19/100\n",
      "274/274 [==============================] - 10s 36ms/step - loss: 0.0401 - val_loss: 0.0407\n",
      "Epoch 20/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0398 - val_loss: 0.0404\n",
      "Epoch 21/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0395 - val_loss: 0.0402\n",
      "Epoch 22/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0392 - val_loss: 0.0394\n",
      "Epoch 23/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0390 - val_loss: 0.0395\n",
      "Epoch 24/100\n",
      "274/274 [==============================] - 10s 37ms/step - loss: 0.0387 - val_loss: 0.0401\n",
      "Epoch 00024: early stopping\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x7f6a283479e8>"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cnn.fit_generator(dg_train, epochs=100, validation_data=dg_valid, \n",
    "                  callbacks=[tf.keras.callbacks.EarlyStopping(\n",
    "                                monitor='val_loss',\n",
    "                                min_delta=0,\n",
    "                                patience=2,\n",
    "                                verbose=1, \n",
    "                                mode='auto'\n",
    "                            )]\n",
    "                 )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "# cnn.save_weights('/home/rasp/cube_home/tmp/test.h5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "cnn.load_weights('/data/weather-benchmark/predictions/saved_models/fccnn_6h.h5')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "Collapsed": "false"
   },
   "source": [
    "## Create predictions\n",
    "\n",
    "Now that we have our model we need to create a prediction NetCDF file. This function does this. \n",
    "\n",
    "We can either directly predict the target lead time (e.g. 5 days) or create an iterative forecast by chaining together many e.g. 6h forecasts."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "def create_predictions(model, dg):\n",
    "    \"\"\"Create predictions for non-iterative model\"\"\"\n",
    "    preds = model.predict_generator(dg)\n",
    "    # Unnormalize\n",
    "    preds = preds * dg.std.values + dg.mean.values\n",
    "    fcs = []\n",
    "    lev_idx = 0\n",
    "    for var, levels in dg.var_dict.items():\n",
    "        if levels is None:\n",
    "            fcs.append(xr.DataArray(\n",
    "                preds[:, :, :, lev_idx],\n",
    "                dims=['time', 'lat', 'lon'],\n",
    "                coords={'time': dg.valid_time, 'lat': dg.ds.lat, 'lon': dg.ds.lon},\n",
    "                name=var\n",
    "            ))\n",
    "            lev_idx += 1\n",
    "        else:\n",
    "            nlevs = len(levels)\n",
    "            fcs.append(xr.DataArray(\n",
    "                preds[:, :, :, lev_idx:lev_idx+nlevs],\n",
    "                dims=['time', 'lat', 'lon', 'level'],\n",
    "                coords={'time': dg.valid_time, 'lat': dg.ds.lat, 'lon': dg.ds.lon, 'level': levels},\n",
    "                name=var\n",
    "            ))\n",
    "            lev_idx += nlevs\n",
    "    return xr.merge(fcs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "fc = create_predictions(cnn, dg_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<xarray.Dataset>\n",
       "Dimensions:  ()\n",
       "Coordinates:\n",
       "    level    int32 850\n",
       "Data variables:\n",
       "    z_rmse   float64 112.8\n",
       "    t_rmse   float64 1.184"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "compute_weighted_rmse(fc, valid).compute()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "def create_iterative_predictions(model, dg, max_lead_time=5*24):\n",
    "    state = dg.data[:dg.n_samples]\n",
    "    preds = []\n",
    "    for _ in range(max_lead_time // dg.lead_time):\n",
    "        state = model.predict(state)\n",
    "        p = state * dg.std.values + dg.mean.values\n",
    "        preds.append(p)\n",
    "    preds = np.array(preds)\n",
    "    \n",
    "    lead_time = np.arange(dg.lead_time, max_lead_time + dg.lead_time, dg.lead_time)\n",
    "    das = []; lev_idx = 0\n",
    "    for var, levels in dg.var_dict.items():\n",
    "        if levels is None:\n",
    "            das.append(xr.DataArray(\n",
    "                preds[:, :, :, :, lev_idx],\n",
    "                dims=['lead_time', 'time', 'lat', 'lon'],\n",
    "                coords={'lead_time': lead_time, 'time': dg.init_time, 'lat': dg.ds.lat, 'lon': dg.ds.lon},\n",
    "                name=var\n",
    "            ))\n",
    "            lev_idx += 1\n",
    "        else:\n",
    "            nlevs = len(levels)\n",
    "            das.append(xr.DataArray(\n",
    "                preds[:, :, :, :, lev_idx:lev_idx+nlevs],\n",
    "                dims=['lead_time', 'time', 'lat', 'lon', 'level'],\n",
    "                coords={'lead_time': lead_time, 'time': dg.init_time, 'lat': dg.ds.lat, 'lon': dg.ds.lon, 'level': levels},\n",
    "                name=var\n",
    "            ))\n",
    "            lev_idx += nlevs\n",
    "    return xr.merge(das)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "fc_iter = create_iterative_predictions(cnn, dg_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "rmse = evaluate_iterative_forecast(fc_iter, valid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<xarray.Dataset>\n",
       "Dimensions:    (lead_time: 20)\n",
       "Coordinates:\n",
       "    level      int32 850\n",
       "  * lead_time  (lead_time) int64 6 12 18 24 30 36 42 ... 90 96 102 108 114 120\n",
       "Data variables:\n",
       "    z_rmse     (lead_time) float64 112.8 173.6 237.9 ... 1.64e+03 1.701e+03\n",
       "    t_rmse     (lead_time) float64 1.184 1.55 1.728 1.888 ... 8.248 8.656 9.056"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse.load()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7efc48127d68>]"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "rmse.z_rmse.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7efc28096e10>]"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "rmse.t_rmse.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "Collapsed": "false"
   },
   "source": [
    "# The end"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
